package
{
//	import flashx.textLayout.formats.BackgroundColor;
/*	
	
	# Project members authenticate over HTTPS to allow committing changes.
		svn checkout https://flashhammertongue.googlecode.com/svn/trunk/ flashhammertongue --username johnnyw66@gmail.com
	
		
	# Non-members may check out a read-only working copy anonymously over HTTP.
		svn checkout http://flashhammertongue.googlecode.com/svn/trunk/ flashhammertongue-read-only
*/
	
	// 640 x 480
	// [SWF(width="640", height= "480", frameRate="60", backgroundColor="#FFFFFF") ]
	
	import caurina.transitions.Tweener;
	
	import com.adobe.utils.*;
	import com.jwdemo.Bullet;
	import com.jwdemo.BulletManager;
	import com.jwdemo.Camera;
	import com.jwdemo.Enemy;
	import com.jwdemo.EnemyManager;
	import com.jwdemo.GameBitMaps;
	import com.jwdemo.GameGUI;
	import com.jwdemo.GameObjectManager;
	import com.jwdemo.GameSounds;
	import com.jwdemo.InfCallBack;
	import com.jwdemo.InfLevel;
	import com.jwdemo.Level1;
	import com.jwdemo.Logger;
	import com.jwdemo.RenderHelper;
	import com.jwdemo.RenderHelperStage3D;
	import com.jwdemo.SpriteSheet;
	import com.jwdemo.TextureAnim;
	import com.jwdemo.TileMap;
	import com.jwdemo.Vector4;
	import com.jwdemo._3DTileMap;
	
	import flash.display.*;
	import flash.display3D.*;
	import flash.display3D.textures.*;
	import flash.events.*;
	import flash.geom.Matrix;
	import flash.geom.Matrix3D;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import flash.text.*;
	import flash.utils.*;
	import flash.utils.getTimer;
	
	
	public class FlashDemo extends Sprite
	{
		
		private var _use3D:Boolean						=	true ;

		// enums? 
		private var dropWidth:Number					=	3 ;

		private static const OVERLAY_MAP:uint			=	0 ;
		private static const OVERLAY_GAMEOBJECTS:uint	=	1 ;
		private static const OVERLAY_HUD:uint			=	10 ;

		private var frames:uint							=	0 ;
		private var tMap:TileMap ;
		private var rHelper:RenderHelper ;
		private var rHelper3D:RenderHelperStage3D ;
		
		private var camera:Camera ;
		private var gameTime:Number 				=	0.0 ;
		private var lastTime:int 					=	0.0 ;
		private var count:int 						=	0 ;
		private var explodeSheet:SpriteSheet 		=	new SpriteSheet(GameBitMaps.GetBitMap("explosion") ,64,64) ;

		private var level1:InfLevel  				=	new Level1() ;

		// TODO - mouse control
		private var dragging:Boolean 				= 	false ;
		private var flipping:Boolean 				= 	false ;

		// CallBack tests
		private var callback:InfCallBack	;
		private var callbackClosure:Function 		=	function() :Function 
														{ 
															var i:int = 0 ;
															return function():int { return i++ ; } ;
														} ;
		private var smokeSheet:SpriteSheet			=	new SpriteSheet(GameBitMaps.GetBitMap("smoke"),64,64) ;
		private var spriteSheet:SpriteSheet			=	new SpriteSheet(GameBitMaps.GetBitMap("sprites"),32,32) ;

		private var exampleSheetAnim:TextureAnim	=	new SpriteSheet(GameBitMaps.GetBitMap("explosion"),64,64).createTextureAnimation(22) ;
		private var smokeAnim:TextureAnim			=	new SpriteSheet(GameBitMaps.GetBitMap("smoke"),64,64).createTextureAnimation(22) ;

		//private var boader:Shape 					= 	new Shape();
		//private var screenDim:Vector4 				=	new Vector4(832,640) ;	// Where do I get this from?
		private var screenDim:Vector4 				=	new Vector4(768,512) ;	// Where do I get this from?

		
		// 3D Stuff

		// the 3d graphics window on the stage
		private var context3D:Context3D;
		private var context3D2:Context3D;

		private var _3dmap:_3DTileMap ;
		private var gameGUI:GameGUI = new GameGUI("GAME ") ; ;

		public var introMessage:Object ;

		public function FlashDemo()
		{
//			gameGUI	=	new GameGUI("Game") ;
	
			addChild(gameGUI) ;
			addEventListener(Event.ADDED_TO_STAGE, stageAdded);
		}
		
		public function stageAdded(e:Event) : void
		{
			if (hasEventListener(Event.ADDED_TO_STAGE))
				removeEventListener(Event.ADDED_TO_STAGE, stageAdded);

			if (_use3D) {
				init3D();
			} else
			{
				initGame() ;
			}
		}
		
		public function addMessageFromLeft(msg:String,duration:int = -1, onC:Function = null) : Object
		{
			
			var tweenWrapper:Object = { x:-800, message:msg} ;
				
			Tweener.addTween(tweenWrapper,
			{	x: screenDim.X()/2, 
				delay:0, 
				time:2, 
				transition: 'easeInOutElastic',
				onStart: function():void {this.x = -800 ;},
				onUpdate: function():void {},
				onComplete: function():void 
				{
					if (duration > 0) 
					{
						Tweener.addTween(tweenWrapper,{x:-800, delay:duration, time:2, transition: 'easeInOutElastic',
						onComplete: function():void 
							{
								if (onC != null) 
								{
									onC() ;
								}
							}
						})
						
					}
				}
			} 
			) ;
		
			return tweenWrapper ;
		}
			
		
		public function init3D() : void
		{
			
			// class constructor - sets up the stage
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align 	= StageAlign.TOP_LEFT;
			
			// and request a context3D from Stage3d
			stage.stage3Ds[0].addEventListener(
				Event.CONTEXT3D_CREATE, onContext3DCreate);
			stage.stage3Ds[0].requestContext3D();

		}

		private function onContext3DCreate(event:Event):void 
		{
			// Remove existing frame handler. Note that a context
			// loss can occur at any time which will force you
			// to recreate all objects we create here.
			// A 3D context loss occurs for instance if you hit
			// CTRL-ALT-DELETE on Windows.			
			// It takes a while before a new context is available
			// hence removing the enterFrame handler is important!
			
			if (hasEventListener(Event.ENTER_FRAME))
				removeEventListener(Event.ENTER_FRAME,onEnterFrame);
			
			// Obtain the current context
			var t:Stage3D = event.target as Stage3D;					
			context3D = t.context3D; 	
			
			if (context3D == null) 
			{
				// Currently no 3d context is available (error!)
				return;
			}
			
			context3D.enableErrorChecking = true; 			// Disabling error checking will drastically improve performance.
			
			//_3dmap		=	new _3DTileMap(context3D,new Level1(), {width : swfWidth, height: swfHeight}) ;
			_3dmap		=	new _3DTileMap(context3D,new Level1(), { width: screenDim.X(), height: screenDim.Y()}) ;

			initGame() ;
		}
	
		public function initGame() : void
		{
			introMessage	=	addMessageFromLeft("FLASH RENEGADE OPS DEMO") ;

			init(level1) ;

			addEventListener(Event.ENTER_FRAME, onEnterFrame);
			stage.addEventListener(KeyboardEvent.KEY_DOWN,
				function():void
				{
					flipping = !flipping ;
					this.rotationX	=	 0	

				}
			) ;	
			stage.addEventListener(MouseEvent.MOUSE_DOWN,
				function(event:MouseEvent):void {
					dragging = true ;
				});

			stage.addEventListener(MouseEvent.MOUSE_UP,
				function(e:MouseEvent):void {
					dragging = false ;
				});

			//var callback	=	new InfCallBack() {  function callBack(obj:Object) : void {
			//		trace("MyInfCallBack") ;		
			//	} } ;

			//boader.graphics.lineStyle(1,0x00000000);
			//boader.graphics.drawRect(0+dropWidth, 0+dropWidth, stage.stageWidth-(Math.max(2*dropWidth, 1)), stage.stageHeight-(Math.max(2*dropWidth, 1)));
			//boader.graphics.endFill();
	
			GameSounds.PlayMusic("backgroundmusic",true); 
		}
		
		private function init1(cLevel:InfLevel) : void 
		{
			rHelper3D	= 	new RenderHelperStage3D(context3D,{width: screenDim.X(), height: screenDim.Y()}) ;

		}
		
		private function init(cLevel:InfLevel) : void 
		{
			//lash.text.TextFormat
			//.TextFormat(font:String=null, size:Object=null, color:Object=null, bold:Object=null, 
			//italic:Object=null, underline:Object=null, url:String=null, target:String=null, align:String=null, leftMargin:Object=null, rightMargin:Object=null, indent:Object=null, leading:Object=null)
				
			var _text:TextField = new TextField();

			var tf:TextFormat = new TextFormat() ; 
			tf.align	= 	TextFormatAlign.CENTER;
			tf.bold		=	true ;
			tf.font		=	"arial" ;
			tf.size		=	16;
			tf.color	=	0xFFFF00 ;
			tf.url		=	"http://ps3coder.com/" ;
		
			_text.x		=	0;
			_text.y		=	screenDim.Y()-40;

			_text.text = "Flash version. Click here for javascript version or cv. Please email for SVN link!";
			_text.setTextFormat(tf) ;

			var lm:TextLineMetrics = _text.getLineMetrics(0) ;

			_text.width = lm.width + 8 ;
			_text.height = lm.height + 8 ;
			
			this.addChild(_text);

			
			//screenDim	=	new Vector4(706,512) ;		//TODO - HOW DO I GET THE 'Stage' SCREEN DIMENSIONS?
			
			rHelper		= 	new RenderHelper(this.graphics) ;
			rHelper3D	= 	new RenderHelperStage3D(context3D,{width: screenDim.X(), height: screenDim.Y()}) ;

			tMap		=	new TileMap(cLevel.getMapData(),GameBitMaps.GetBitMap(cLevel.getTileMapImageName()),new Vector4(706,512),new Vector4(64,64)) ;

			BulletManager.Init() ;			//TODO Move Management over to GameObjectManager
			GameObjectManager.Init() ;

			// Initialise EnemyManager - and add a few helicopters	

			EnemyManager.Init(cLevel.getEnemies()) ;	// Note -ignoring the real data for now
			
			EnemyManager.Add(new Enemy(new Vector4(1200+32,1512),0,1.1)) ;
			EnemyManager.Add(new Enemy(new Vector4(1200,1512),0.09)) ;
			EnemyManager.Add(new Enemy(new Vector4(1200,1512+32),0,-0.5)) ;

			// Create a camera - which follows one of the helicopters.

			camera		=	new Camera(screenDim,tMap.getDim(),EnemyManager.getEnemy(0)) ;

			exampleSheetAnim.play(true,false) ;
			smokeAnim.play(true,false) ;

		}
		

		private function onEnterFrame(e:Event) : void {
			var now:int			=	getTimer() ;
			var elapsedTime:int =	now - lastTime;
			var dt:Number		= 	elapsedTime/1000.0;
			lastTime			=	now ;
			frames++ ;
			gameTime				=	gameTime + dt ;

			upDate(dt) ;
			draw() ;
			//draw3d() ;

			//rHelper.drawText("time "+(getTimer() - now), screenDim.X()*0.5, 60,16,"middle","top") ;

			rHelper.drawText("John Wilson - 2012", screenDim.X()*0.5, 60,16,"middle","top") ;
			rHelper.drawText("Two Renders of Tilemap - 1: flash.display.drawTriangles. 2: Stage3D AGAL", screenDim.X()*0.5, 80,16,"middle","top") 			//rHelper.drawText("fps = "+int(frames/gameTime), screenDim.X()*0.5, 100,16,"middle","top") ;

			rHelper.drawText("FPS = "+int(0.5+(frames/gameTime))+" "+rHelper3D, screenDim.X()*0.5, 120,16,"middle","top") 			//rHelper.drawText("fps = "+int(frames/gameTime), screenDim.X()*0.5, 100,16,"middle","top") ;

		}

			
		private function upDate(dt:Number,cb:InfCallBack = null) : void
		{
			
			//this.rotationY	=	 0 + Math.sin(gameTime*6/8)*(2 - 0) ;
			//this.rotationZ	=	 0 + Math.sin(gameTime*6/8)*(2 - 0) ;
			if (flipping)
				this.rotationX	=	 0 + Math.sin(gameTime*6/20)*(45 - 120) ;

			camera.update(dt) ;
			EnemyManager.Update(dt) ;
			BulletManager.Update(dt) ;		// TODO Move Management over to GameObjectManager
			GameObjectManager.Update(dt) ;
			
			// Show off spritesheet animation
			exampleSheetAnim.update(dt) ;
			smokeAnim.update(dt) ;
		}
		
		
		
		var frameSheet:uint = 0 ;
		
		private function draw3d() : void
		{
			rHelper3D.start();
			rHelper3D.drawSheet(smokeSheet,256,200,frameSheet,frameSheet % 360,4,4,1) ;
			for (var i:uint = 0 ; i < 20; i++) {
				for (var j:uint = 0 ; j < 20 ; j++)
				{
					rHelper3D.drawSheet(spriteSheet,i*64,j*64,int(i*j % 10),frameSheet % 360,1.5,1.5) ;
				}
			}
			frameSheet++ ;				
			rHelper3D.end();
		}
		
		
		private function draw() : void
		{

			var frame:int = 0 ;
			rHelper.setOverlay(OVERLAY_MAP) ;				// Use RenderHelper 2DCamera for  Map Overlay.
			
	
			// Work out top/left from camera
			var camerapos:Object	=	 camera.getTopLeft() ;

			// Render TileMap from that corner.
			rHelper.clearContext() ;

			
			if (_use3D) 
				_3dmap.Render(int(camerapos.x),int(camerapos.y)) ;
				
				
			tMap.Render(rHelper,int(camerapos.x),int(camerapos.y))  ;
				
			
			// Render Game Elements Overlay
			
			rHelper.setOverlay(OVERLAY_GAMEOBJECTS) ;				// Using a 2nd Overlay - set RenderHelper's 2D Camera.
												// from Game Camera.
			rHelper.camera2dSetPostition(int(camerapos.x),int(camerapos.y)) ;

			// EnemyManager.Render
			EnemyManager.Render(rHelper) ;
			BulletManager.Render(rHelper) ;		// TODO Move Management over to GameObjectManager
			GameObjectManager.Render(rHelper) ;

			var smokeInfo:Object = smokeAnim.getRenderTexture() ;
			rHelper.drawSheet(smokeInfo.sheet,1512,1832,smokeInfo.frame,0,3,3) ;
	
			// Render HUD overlay
			
			rHelper.setOverlay(OVERLAY_HUD) ;

			//rHelper.drawText("FLASH RETRO GAME DEMO", screenDim.X()*0.5, 4,32,"middle","top") ;
			rHelper.drawText(introMessage.message, introMessage.x, 4,32,"middle","top") ;
			
//			rHelper.drawText("tweenMe.x = "+int(tweenMe.x), screenDim.X()*0.5, screenDim.Y()-100,16,"middle","top") ;


			if (dragging) {
				rHelper.drawCircle(this.mouseX,this.mouseY,4) ;
				rHelper.drawText(""+int(this.parent.mouseX)+","+int(mouseX),this.mouseX+20,this.mouseY) ;

			}

			if (exampleSheetAnim.isPlaying())
			{
				var textureInfo:Object = exampleSheetAnim.getRenderTexture() ;
				rHelper.drawSheet(textureInfo.sheet,0,0,textureInfo.frame) ;
				//rHelper.drawCircle(0,0,2) ;
				//rHelper.drawCircle(560,374,5) ;
			}


	
		}
		
	
		
		// Test Matrix 
		public function drawTest() : void
		{
			var mtx:Matrix	=	new Matrix() ;
			var angle:Number = 45 ;
			var abt:Point = new Point(80,20) ;
			
			mtx.identity() ;
			mtx.translate(-abt.x, -abt.y) ;
			mtx.rotate(angle*Math.PI/180) ;
			mtx.scale(2,2) ;
			mtx.translate(256,200) ;

			rHelper.drawLine(256,0,256,400) ;
			rHelper.drawLine(0,200,512,200) ;
				
			var p1:Point = new Point(0,0) ;
			var p2:Point = new Point(120,0) ;
			var p3:Point = new Point(120,80) ;
			var p4:Point = new Point(0,80) ;
			var cen:Point = new Point(0,0) ;
			
			var pts:Vector.<Point> = new Vector.<Point>() ;
			pts.push(p1) ;
			pts.push(p2) ;
			pts.push(p3) ;
			pts.push(p4) ;
			rHelper.drawPoly(pts,0xff0000) ;
			rHelper.drawCircle(cen.x,cen.y,1) ;

			rHelper.drawCircle(abt.x,abt.y,4,0xffffff) ;

			var tp1:Point = mtx.transformPoint(p1)  ;
			var tp2:Point = mtx.transformPoint(p2)  ;
			var tp3:Point = mtx.transformPoint(p3)  ;
			var tp4:Point = mtx.transformPoint(p4)  ;
			var tc :Point = mtx.transformPoint(cen) ;
			var tabt:Point = mtx.transformPoint(abt) ;
			
			var tpts:Vector.<Point> = new Vector.<Point>() ;
			tpts.push(tp1) ;
			tpts.push(tp2) ;
			tpts.push(tp3) ;
			tpts.push(tp4) ;
			rHelper.drawPoly(tpts,0xffff00) ;	
			rHelper.drawCircle(tc.x,tc.y,1) ;
			rHelper.drawCircle(tabt.x,tabt.y,4,0xffffff) ;
			
		}
	
 }
}